﻿using System;
using Real = System.Double;

namespace LinearAlgebra.Matrices
{
	public partial class Matrix
	{						
		/// <summary>
		/// Compares two matrices using a standard (*reasonable*) maxDiff
		/// </summary>				
		/// <param name="B">The matrix being compared</param>
		/// <param name="maxDiff">The matrix being compared</param>
		/// <returns>Whether they are considered equivalent</returns>
		public bool Equals( Matrix B, Real maxDiff ) {							
			return AreMatricesEqual( this, B, maxDiff );			
		}		
		
		/// <summary>
		/// Tests for referential equality
		/// </summary>		
		public override bool Equals( object obj )
		{
			if ( ReferenceEquals(null, obj) )
				return false;
			if ( ReferenceEquals(this, obj) )
				return true;
			if ( obj.GetType() != typeof (Matrix) )
				return false;
			return Equals( (Matrix) obj);
		}

		/// <summary>
		/// Check's this matrices elements to see if it is symetrical
		/// </summary>
		/// <param name="maxDiff">The max difference between any two elements</param>		
		public bool IsSymmetric ( Real maxDiff )
		{
			if( this.M != this.N )
				return false;
			for( int i = 0; i < this.M; i++ )			
				for (int j = 0; j < this.N; j++)				
					if( i == j) {
						continue; //performance optimization, comparing an int is faster than the operation below
					}
					else {
						if( Math.Abs( this[i][j] - this[j][i] ) > maxDiff )					
							return false;
					}
			return true;
		}

		/// <summary>
		/// Compares two matrices using a maximum allowable difference(epsilon)
		/// </summary>	
		/// <param name="A">The first matrix</param>
		/// <param name="B">The second matrix</param>
		/// <param name="maxDiff">The tolerance between values at the same index</param>
		/// <returns>A boolean value indicating a positive assertion of equality</returns>
		public static bool AreMatricesEqual( Matrix A, Matrix B, Real maxDiff )
		{
			if( ( A.RowCount != B.RowCount ) || ( A.ColumnCount != B.ColumnCount ) ) //the dimensions of the matrices do not match
				throw new Exception( "Matrices are not of the same dimensions." );			

			for( int i = 0; i < A.RowCount; i++ )
			{				
				Real diff; //do not declare in inner scope, this makes things faster
				for( int j = 0; j < A.ColumnCount; j++ ) {
					diff = Math.Abs( (A[i][j] - B[i][j]) );					
					if( diff > maxDiff )
						return false;
				}
			}
			return true;
		}
		
		/// <summary>
		/// Returns the hashcode for the matrix
		/// </summary>		
		public override int GetHashCode() {
			return GetHashCode();
		}
	}
}
